/*
 * $Id: VTCLdapAuthenticator.java 1147 2011-07-08 10:42:26Z jyang $
 * 
 * Copyright (c) 2001-2008 Accentrix Company Limited. All Rights Reserved.
 * 
 * Accentrix Company Limited. ("Accentrix") retains copyright on all text, source
 * and binary code contained in this software and documentation. Accentrix grants
 * Licensee a limited license to use this software, provided that this copyright
 * notice and license appear on all copies of the software. The software source
 * code is provided for reference purposes only and may not be copied, modified 
 * or distributed.
 * 
 * THIS SOFTWARE AND DOCUMENTATION ARE PROVIDED "AS IS," WITHOUT ANY WARRANTY OF
 * ANY KIND UNLESS A SEPARATE WARRANTIES IS PURCHASED FROM ACCENTRIX AND REMAINS
 * VALID.  ALL EXPRESS OR IMPLIED CONDITIONS, REPRESENTATIONS AND WARRANTIES,
 * INCLUDING ANY IMPLIED WARRANTY OF MERCHANTABILITY, FITNESS FOR A PARTICULAR
 * PURPOSE OR NON-INFRINGEMENT, ARE HEREBY EXCLUDED. ACCENTRIX SHALL NOT BE LIABLE
 * FOR ANY DAMAGES SUFFERED BY LICENSEE AS A RESULT OF USING OR MODIFYING THE
 * SOFTWARE OR ITS DERIVATIVES.
 * 
 * IN NO EVENT WILL ACCENTRIX BE LIABLE FOR ANY LOST REVENUE, PROFIT OR DATA, OR
 * FOR DIRECT, INDIRECT, SPECIAL, CONSEQUENTIAL, INCIDENTAL OR PUNITIVE DAMAGES,
 * HOWEVER CAUSED AND REGARDLESS OF THE THEORY OF LIABILITY, ARISING OUT OF THE
 * USE OF OR INABILITY TO USE SOFTWARE, EVEN IF ACCENTRIX HAS BEEN ADVISED OF THE
 * POSSIBILITY OF SUCH DAMAGES.
 */
package com.lightsaber.trade.core.common.security;

import java.util.Hashtable;

import javax.naming.AuthenticationException;
import javax.naming.Context;
import javax.naming.NamingEnumeration;
import javax.naming.NamingException;
import javax.naming.directory.DirContext;
import javax.naming.directory.InitialDirContext;
import javax.naming.directory.SearchControls;
import javax.naming.directory.SearchResult;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.ldap.core.ContextSource;
import org.springframework.ldap.core.DirContextAdapter;
import org.springframework.ldap.core.DirContextOperations;
import org.springframework.security.authentication.BadCredentialsException;
import org.springframework.security.core.Authentication;
import org.springframework.security.ldap.authentication.AbstractLdapAuthenticator;

public class VTCLdapAuthenticator extends AbstractLdapAuthenticator {

    private final static Logger log = LoggerFactory.getLogger(VTCLdapAuthenticator.class);

    private static String LDAP_URL = "ldap://192.168.247.20:389";
    private static String ADMIN_DN = "cn=admin,ou=users,dc=axtest,dc=com";
    private static String ADMIN_PASSWORD = "Password1";
    private static String USER_BASE_DN = "ou=users,dc=axtest,dc=com";
    private static final String authenticationMode = "simple";
    private static final String contextFactoryMode = "com.sun.jndi.ldap.LdapCtxFactory";

    public VTCLdapAuthenticator(ContextSource contextSource) {
        super(contextSource);
    }

    @Override
    public DirContextOperations authenticate(Authentication authentication) {

        String userName = authentication.getName();
        String userPassword = (String) authentication.getCredentials();

        boolean result = false;
        DirContextOperations user = null;
        

        try {
            result = ADAuthenticate(LDAP_URL, ADMIN_DN, ADMIN_PASSWORD, USER_BASE_DN, userName,
                    userPassword);
            log.info("result: {}", result);
        } catch (Exception e) {
            log.error(e.getMessage());
        }

        if (result) {
            user = new DirContextAdapter("cn=" + userName + "," + USER_BASE_DN);
            user.addAttributeValue("name", userName);
            user.addAttributeValue("userPassword", userPassword);
        } else {
            throw new BadCredentialsException(messages.getMessage("VTCLdapAuthenticator",
                    "Bad credentials"));
        }

        return user;
    }

    private boolean ADAuthenticate(String providerURL, String adminDN, String adminPassword,
            String userBaseDN, String userName, String userPassword) throws Exception {

        Hashtable env = new Hashtable(5, 0.75f);
        env.put(Context.INITIAL_CONTEXT_FACTORY, contextFactoryMode);
        env.put(Context.PROVIDER_URL, providerURL);
        env.put(Context.SECURITY_AUTHENTICATION, authenticationMode);
        env.put(Context.SECURITY_PRINCIPAL, adminDN);
        env.put(Context.SECURITY_CREDENTIALS, adminPassword);
        DirContext ctx = null;
        DirContext ctxAuth = null;
        boolean returnValue = false; // Default : Not authorized

        try {
            ctx = new InitialDirContext(env); // Binding to the Active Directory
                                              // (AD) Server

            SearchControls cons = new SearchControls();
            cons.setSearchScope(SearchControls.SUBTREE_SCOPE);
            NamingEnumeration results = ctx.search(userBaseDN, "(cn=" + userName + ")", cons);

            if (results != null && results.hasMore()) {
                try {
                    String myContext = ((SearchResult) results.next()).getName();
                    Hashtable env2 = new Hashtable(5, 0.75f);
                    env2.put(Context.INITIAL_CONTEXT_FACTORY, contextFactoryMode);
                    env2.put(Context.PROVIDER_URL, providerURL);
                    env2.put(Context.SECURITY_AUTHENTICATION, authenticationMode);
                    env2.put(Context.SECURITY_PRINCIPAL, myContext + "," + userBaseDN);
                    env2.put(Context.SECURITY_CREDENTIALS, userPassword);
                    ctxAuth = new InitialDirContext(env2);

                    if (ctxAuth != null)
                        returnValue = true;
                    else
                        returnValue = false; // Retrieve the Context. i.e.
                                             // Authorized
                    ctxAuth.close();
                    ctx.close();

                } catch (AuthenticationException e) {
                    returnValue = false;
                    System.out.println(e.getMessage());
                    e.printStackTrace();
                } finally {

                }
            } else {
                returnValue = false;
            }
        } catch (NamingException e) {
            returnValue = false;
            System.out.println(e.getMessage());
            e.printStackTrace();
        } finally {
            if (ctx != null) {
                try {
                    ctx.close();
                } catch (Exception e) {
                    throw new Exception("Problem in binding AD server.");
                }
            }
            if (ctxAuth != null) {
                try {
                    ctxAuth.close();
                } catch (Exception e) {
                    throw new Exception("Problem in binding AD server.");
                }
            }
        }

        return returnValue;
    }
}
